/***************************************************************************
 *   Copyright (C) 2006 by Archimedes Projekt   *
 *   thelsb@gmail.com   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#ifndef _GLOBALS_
#define _GLOBALS_
#include <QDataStream>
#include <QByteArray>
#include <exception>
#include "telemetryservcon.h"
#define CAMCON_FIXED 1 //fixed sesor section size (still TBD)
#define PODCON_FIXED 1
#define SERVCON_FIXED 1
#define SYNC_SIZE 4 //sync word size



/**
 A generic exception class for Miriam
*/
class MException : public std::exception
{
 private:
  QString m_text;
  public:
   MException() throw(){}
   MException(const QString &text) throw() :m_text(text){}
   ~MException() throw() {}
  void setText(const QString &text) throw() {  m_text = text;  }
  virtual const QString & qwhat() throw()
  {
   if(!m_text.isEmpty())
     return m_text;
   m_text = what() ;
   return m_text;
  }
};

namespace TM {
/**
  Sensor block
 */
class TMSensorBlock
{
public:
 typedef enum SENSOR { Atmos,AMS,PODCAM,MAGNETOMETER,TEMPx };
private:
 quint32 m_size;
 SENSOR m_sensor;
 quint32 m_blockNum;
 QByteArray m_data;
public: 
 TMSensorBlock(SENSOR sensor):m_size(0),m_sensor(sensor){}
 /** Copy constructor*/
 TMSensorBlock(const TMSensorBlock &instance)
 {
  m_sensor = instance.sensor();
  m_size = instance.size();
  m_blockNum = instance.blockNum();
  m_data = instance.m_data;
 }

 const SENSOR & sensor() const { return m_sensor; }
 /** Returns the size of the data section.
  This is used when reading data for a sensor in the variable section.
  Based on this this size the operator<<() will know how many bytes to read. */
 const quint32 & size() const  { return m_size; }
 const quint32 & blockNum() const { return m_blockNum; }
 QByteArray & data() { return m_data; }
 void setSensor(const SENSOR &sensor) { m_sensor = sensor; }
 void setSize(const quint32 &size ) { m_size = size; }
 /** Reads 'm_size' bytes from the stream into 'm_data' */
 QByteArray & operator<<(QDataStream &s) throw (MException)
 {
  if(m_size)
   s.readRawData(m_data.data(),m_size);
  else throw MException("TMSensorBlock: can't asign data to null size QByteArray 'm_data'") ;
 }
 

};

/*!
 Abstract Miriam telemetry data block class
*/
class MDataBlock
{
public:
 typedef enum TYPE { CAMCON, PODCON, SERVCON, TERRACON, ERR };
private:
 QList<TMSensorBlock> m_constSensors,
                      m_varSensors;
 //quint8 m_syncWord[SYNC_SIZE];
 quint32 m_blockNum;
 QByteArray m_bdata;
 TYPE m_type;
 quint16 m_crc;
public: 
 MDataBlock(TYPE type):m_blockNum(0),m_type(type)
 { }
 /*! \fn MDataBlock(const MDataBlock &instance)
  copy constructor 
 */
 MDataBlock(const MDataBlock &instance)
 {
  this->m_type = instance.m_type;
  this->m_blockNum = instance.m_blockNum;
  this->m_constSensors = instance.m_constSensors;
  this->m_varSensors = instance.m_varSensors;
  this->m_crc = instance.m_crc;
 }
 /** assignment operator */
 MDataBlock & operator=(const MDataBlock &src) throw(MException)
 {
  this->m_type = src.m_type;
  //memcpy(m_syncWord,src.m_syncWord,SYNC_SIZE);
  this->m_blockNum = src.m_blockNum;
  this->m_constSensors = src.m_constSensors;
  this->m_varSensors = src.m_varSensors;
  this->m_crc = src.m_crc;
  return *this;
 }
 ~MDataBlock()
 {  }
 /** Returns self as QByteArray.
    Allows the use of QDataStream::operator<<() */
 QByteArray & byteArray()
 {
  m_bdata.resize(sizeof(*this));
  memcpy(&m_bdata,this,sizeof(*this));
  return m_bdata;
 }
 const quint32 & blockNum()const { return m_blockNum; }
 void setBlockNum(const quint32  &num) { m_blockNum = num; }
 const TYPE & type() const { return m_type; }
 /** Adds a sensor to the fixed sensor section of the telemetry block */
 void addConstSensor(const TMSensorBlock &sensor)
 {
  m_constSensors<<sensor;
 }
 /**  Adds a sensor to the variable sensor section of the telemetry block */
 void addVarSensor(const TMSensorBlock &sensor)
 {
  m_varSensors<<sensor;
 }

 const QList<TMSensorBlock> & constSensors() const { return m_constSensors; }
 const QList<TMSensorBlock> & varSensors() const { return m_varSensors; }
};

QDataStream & operator>>(QDataStream &s, MDataBlock *dataBlock);
QDataStream & operator<<(QDataStream &s, MDataBlock *dataBlock);
QDataStream & operator<<(QDataStream &s, MDataBlock::TYPE blockType);
QDataStream & operator>>(QDataStream &s, MDataBlock::TYPE blockType);

};


#endif